/************************************************************
 * Copyright (C), 2020-2030, ripnano. Co., Ltd.
 * FileName:        utility_api.h
 * Author:			Dan Yin
 * Date:            2024-08-01
 * Description:		Public methods for processing data on UI
 * Version:			1.0.0.0
 **********************************************************/

#ifndef UTILITY_API_H
#define UTILITY_API_H

#include <iostream>
#include <QObject>
#include <QtDebug>
#include <QQueue>
#include <QList>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
#include "utils/defines/def_business_rules.h"
#include "ui/factory/extract_debug/mvc/extract_data_define.h"
#include "ui/factory/process_debug/mvc/process_data_define.h"
#include "ui/defines/global.h"

enum EUM_AREA_TYPE {E_AT_NONE, E_AT_EXTRACT, E_AT_SPECIMEN, E_AT_REACTION};
enum EUM_MOVE_TYPE {E_MT_NONE, E_MT_PIERCING, E_MT_SLEEVE, E_MT_TIPS};

class UtilityAPI : public QObject
{
    Q_OBJECT

    struct ST_MOTION_INFO {
        int nSrcHoleNumber;
        int nTarHoleNumber;
        int nPreMoveType;
        int nCurMoveType;
        int nPreAreaType;
        int nCurAreaType;

        ST_MOTION_INFO(){
            clear();
        }
        void clear() {
            nSrcHoleNumber = 0;
            nTarHoleNumber = 0;
            nPreMoveType = E_MT_NONE;
            nCurMoveType = E_MT_NONE;
            nPreAreaType = E_AT_NONE;
            nCurAreaType = E_AT_NONE;
        }
    };

public:
    // Get an instance of "UtilityAPI" class, if exist, return it
    static UtilityAPI* getInstance(QObject *pParent = nullptr);

    // The default destructor
    virtual ~UtilityAPI() {};

    // Split extract procedure action & push into a action queue
    int splitProcedureAction(QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, ST_MOTOR_STATE stMotorState);

    // Split extract procedure action & push into a action queue
    int splitProcedureAction(QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, const QList<ST_STEP_INFO> &lstModelData, int nKitType);

    // Split process procedure action & push into a action queue
    int splitProcedureAction(QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, const QList<STC_PROCESS_TEST_INFO> &lstModelData);

    // Split process procedure action & push into a action queue
    int splitProcedureAction(QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, const QString &sProcedureContent);

    // Cancel process procedure and return a list of action queue
    int splitProcedureActionForCancelling(QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction);

    // Get the step of extract procedure by process content
    int getExtractStepInfo(QList<ST_STEP_INFO> &lstModelData, const QString &sProcedureContent);

    // Get PCR params from procedure struct
    int getPcrParamsInfo(QList<ST_PCR_PARAMS> &lstPcrParams, const ST_PCR_PROCEDURE &stPcrProc);

    // Convert struct data to json data
    int struct2Json(const ST_PCR_PROCEDURE &stPcrProc, QByteArray &baJsonContext);

    // Transfer json string to data struct
    int json2Struct(const QByteArray &baJsonContext, ST_PCR_PROCEDURE &stPcrProc);

    // Transfer data map to json data
    int map2Json(QByteArray &baJsonData, const QMap<unsigned int, QVector<QPointF>> &mapValue, bool bTempChart);

    // Convert command ID to command text
    QString convertCmdId2Text(const int nCmdIdx) const;

    // Convert command text to command ID
    int convertCmdText2Id(const QString sCmdText) const;

    // Convert step falg to step name
    QString convertStepFlag2Name(const QString sStepFlag) const;

    // Parsing a string into list
    template<class T>
    void string2List(QList<T> &lstOutput, QString sInput, QString sSymbol) {
        lstOutput.clear();

        if(!sInput.isEmpty()) {
            QStringList lstSplit = sInput.split(sSymbol);
            for(int i=0; i<lstSplit.size() - 1; i++) {
                lstOutput << QVariant(lstSplit.at(i)).value<T>();
            }
        }
    }

    // Parsing a list into string
    template<class T>
    void list2String(QString sOutput, const QList<T> &lstInput, QString sSymbol) {
        sOutput = "";

        if(0 < lstInput.size()) {
            for(int i=0; i<lstInput.size(); i++) {
                sOutput += QString::number(lstInput.at(i));
                sOutput += sSymbol;
            }
        }
    }

    // Get the error level info by error type number
    QString getErrorLevelByType(int nErrLevel);

    // Get the error info by error code number from inspect
    QString getErrorDescByCodeInspect(long nErrNum);

    // Get the time consuming for testing
    float getTimeConsuming();

private:
    // The default constructor
    explicit UtilityAPI(QObject *pParent = nullptr) { m_pParent = pParent; };

    // Push a element into queue
    int _insertFlowAction(QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, ST_MOTOR_STATE &stMotorOffset, int nCmdIdx, int nStepIdx, int nCmdID, float fParam = -1, float fParam2 = -1, float fParam3 = -1, float fParam4 = -1);

    // Obtain the absolute offset between initialize position
    int _getHoleAbsoluteOffset(int nKitType, int nTarHoleNumber, bool bPCR);

    // Reset motors
    void _resetMotors(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, bool bInit);

    // Grap/Discard drivepipe
    void _switchDrivepipe(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, bool bEnable);

    // Grap/Discard tipspipe
    void _switchTipspipe(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, bool bEnable);

    // Move the ironpipe & piercing
    void _doPiercing(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nKitType);

    // Silent for a moment
    void _doSilent(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nDuration, int nKitType);

    // Move the magnetic sleelve & mixing
    void _doSleelveMixing(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nDuration, int nMotorSpeed, int nKitType, int nVolumeValue);

    // Move the magnetic rod & filtering the magnetic bead
    void _doMagnetFiltering(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nDuration, int nKitType, int nVolumeValue);

    // Move the tipspipe & suction
    void _doTipSuctionSpit(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nVolumeValue, bool bSuction, int nKitType);

    // Move the tipspipe & mxing
    void _doTipMixing(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nVolumeValue, int nCycles, int nKitType);

    // Start/stop heating
    void _switchHeating(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, int nHoleNumber, int nKitType, bool bEnable, float fHeatValue = 0);

    // Obtain adjacent action info
    int _getAdjacentActionInfo(ST_MOTION_INFO &stMotionInfo, const QList<ST_STEP_INFO> &lstModelData, int nRowIdx);

    // Move the tray to target holes for graping pipe
    bool _moveTrayMotorForPipe(ST_MOTOR_STATE &stT1cMotorOffset, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, int nActionType);

    // Move the tray to target holes
    void _moveTrayMotorForAction(ST_MOTOR_STATE &stMotorState, QQueue<ST_FLOW_PROC_ACTION> &queFlowProcAction, QList<QString> &lstAction, int &nCmdIdx, int nStepIdx, const ST_MOTION_INFO &stMotionInfo, int nKitType);

protected:
    float   m_fTimeConsuming = 0.0;

private:
    QObject *m_pParent = nullptr;
};

#endif // UTILITY_API_H
